// by Wei Pan

#include <iostream>
using namespace std;

struct T {
    virtual T operator+(const T& t)=0;

};

struct T1 : public T {
    float val;
    T1 (float v) : val(v) {}
    T1 operator+(const T &t) {
		const T1& t1=dynamic_cast<const T1&>(t);
        cout << "T1 +" << endl;
        return (val + t1.val);
    }
};

struct T2 : public T {
    int val;
    T2 (int v) : val(v) {}
    T2 operator+(const T &t) {
		const T2& t2=dynamic_cast<const T2&>(t);
        cout << "T2 +" << endl;
        return (val + t2.val);
    }
};

ostream& operator<<(ostream& os, const T1& t) {
    cout << t.val;
    return os; 
}

ostream& operator<<(ostream& os, const T2& t) {
    cout << t.val;
    return os; 
}


int main()
{
    T1 a(1.1);
    T1 b(2.2);
    T2 c(3);
    T2 d(4);

    T *pa = &a; 
    T *pb = &b; 
    T *pc = &c; 
    T *pd = &d;
	const T& ra=a;
	const T& rb=b;

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "a + b = " << a + b << endl;
    cout << "a + b = " << ra + rb << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    
    
    return 0;
}
